package com.heima.article.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heima.article.mapper.ApArticleConfigMapper;
import com.heima.article.mapper.ApArticleContentMapper;
import com.heima.article.mapper.ApArticleMapper;
import com.heima.article.service.ApArticleService;
import com.heima.common.constants.ArticleConstants;
import com.heima.common.redis.CacheService;
import com.heima.file.service.FileStorageService;
import com.heima.model.article.dtos.ArticleDto;
import com.heima.model.article.dtos.ArticleHomeDto;
import com.heima.model.article.pojos.ApArticle;
import com.heima.model.article.pojos.ApArticleConfig;
import com.heima.model.article.pojos.ApArticleContent;
import com.heima.model.article.vos.ApArticleConScore;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.search.vos.SearchArticleVo;
import freemarker.template.Configuration;
import freemarker.template.TemplateException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.kafka.clients.admin.KafkaAdminClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.util.Date;
import java.util.HashMap;
import java.util.List;

@Service
@Transactional
@Slf4j
public class ApArticleServiceImpl  extends ServiceImpl<ApArticleMapper, ApArticle> implements ApArticleService {

    // 单页最大加载的数字
    private final static short MAX_PAGE_SIZE = 50;

    @Autowired
    private ApArticleMapper apArticleMapper;

    @Autowired
    private ApArticleConfigMapper apArticleConfigMapper;

    @Autowired
    private ApArticleContentMapper apArticleContentMapper;

    /**
     * 根据参数加载文章列表
     * @param loadtype 1为加载更多  2为加载最新
     * @param dto
     * @return
     */
    @Override
    public ResponseResult load(Short loadtype, ArticleHomeDto dto) {
        //1.校验参数
        Integer size = dto.getSize();
        if(size == null || size == 0){
            size = 10;
        }
        size = Math.min(size,MAX_PAGE_SIZE);
        dto.setSize(size);

        //类型参数检验
        if(!loadtype.equals(ArticleConstants.LOADTYPE_LOAD_MORE)&&!loadtype.equals(ArticleConstants.LOADTYPE_LOAD_NEW)){
            loadtype = ArticleConstants.LOADTYPE_LOAD_MORE;
        }
        //文章频道校验
        if(StringUtils.isEmpty(dto.getTag())){
            dto.setTag(ArticleConstants.DEFAULT_TAG);
        }

        //时间校验
        if(dto.getMaxBehotTime() == null) dto.setMaxBehotTime(new Date());
        if(dto.getMinBehotTime() == null) dto.setMinBehotTime(new Date());
        //2.查询数据
        List<ApArticle> apArticles = apArticleMapper.loadArticleList(dto, loadtype);

        //3.结果封装
        ResponseResult responseResult = ResponseResult.okResult(apArticles);
        return responseResult;
    }

    @Override
    @Transactional
    public ResponseResult saveArticle(ArticleDto dto) {
        log.info("保存文章开始：{}",dto);
        if (dto == null){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_REQUIRE);
        }
        ApArticle apArticle = new ApArticle();
        BeanUtils.copyProperties(dto,apArticle);

        if (apArticle.getId() != null){
            updateById(apArticle);

            ApArticleContent articleContent = apArticleContentMapper.selectOne(Wrappers.<ApArticleContent>lambdaQuery().eq(ApArticleContent::getArticleId, apArticle.getId()));
            articleContent.setContent(dto.getContent());
            apArticleContentMapper.updateById(articleContent);

            //渲染模板文件上传到minio
            makeHtmlAndUploadToMinIO(apArticle,dto);
            log.info("更新文章成功：{}",apArticle);
        }else {
            apArticleMapper.insert(apArticle);
            apArticleConfigMapper.insert(new ApArticleConfig(apArticle.getId()));

            ApArticleContent content = new ApArticleContent();
            content.setArticleId(apArticle.getId());
            content.setContent(dto.getContent());
            apArticleContentMapper.insert(  content);
            //渲染模板文件上传到minio
            makeHtmlAndUploadToMinIO(apArticle,dto);

            log.info("保存文章成功：{}",apArticle);
        }

        return ResponseResult.okResult(apArticle.getId());
    }

    @Autowired
    private CacheService cacheService;
    @Override
    public ResponseResult load2(Short loadtype, ArticleHomeDto dto) {

        String jsonStr = cacheService.get(ArticleConstants.HOT_ARTICLE_FIRST_PAGE + dto.getTag());
        log.info("缓存数据：{}",jsonStr);
        if(StringUtils.isNotBlank(jsonStr) && !jsonStr.equals("[]")){
            log.info("缓存数据为空：{}",jsonStr);
            List<ApArticleConScore>hotArticleVoList = JSON.parseArray(jsonStr, ApArticleConScore.class);
            ResponseResult responseResult = ResponseResult.okResult(hotArticleVoList);
            return responseResult;
        }else {
            return load(loadtype,dto);
        }
    }

    @Autowired
    private FileStorageService fileStorageService;
    @Autowired
    private Configuration configuration;
    @Async
    public void makeHtmlAndUploadToMinIO(ApArticle apArticle, ArticleDto dto) {

//        ApArticleContent apArticleContent = apArticleContentMapper
//                .selectOne(Wrappers.<ApArticleContent>lambdaQuery().eq(ApArticleContent::getArticleId, a));
        if (!apArticle.getTitle().isEmpty() && !dto.getContent().isEmpty()) {
            ApArticle dbArticle = getById(apArticle.getId());
            //存在就删除MinIo文章模板
            if (dbArticle.getStaticUrl() != null){
                log.info("删除静态html{}", apArticle.getId());
                fileStorageService.delete(dbArticle.getStaticUrl());
            }

            log.info("开始生成文章静态页面：{}", apArticle.getId());

            HashMap<String, Object> map = new HashMap<>();
            JSONArray jsonArray = JSONArray.parseArray(dto.getContent());
            map.put("content", jsonArray);

            StringWriter out = new StringWriter();
            try {
                configuration.getTemplate("article.ftl").process(map, out);
            } catch (TemplateException e) {
                throw new RuntimeException(e);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            InputStream is = new ByteArrayInputStream(out.toString().getBytes());

            String htmlFilePath = fileStorageService.uploadHtmlFile("", apArticle.getId() + ".html", is);

            System.out.printf("htmlFilePath:" + htmlFilePath);
//        ApArticle article = new ApArticle();
//        article.setId(1302864436297482242L);
            apArticle.setStaticUrl(htmlFilePath);
            apArticleMapper.updateById(apArticle);
             log.info("生成文章静态页面成功：{}", apArticle.getId());

             //发送消息给es进行索引文章创建
            apArticleSyncEs(apArticle, htmlFilePath, dto.getContent());
        }


    }

    @Autowired
    private KafkaTemplate<String, String> kafkaTemplate;
    private void apArticleSyncEs(ApArticle apArticle, String htmlFilePath, String content) {
        log.info("发送消息给es进行索引文章创建，文章id：{}", apArticle.getId());
        log.info("htmlFilePath:{},文章内容：{}", htmlFilePath, htmlFilePath);

        SearchArticleVo articleVo = new SearchArticleVo();
        BeanUtils.copyProperties(apArticle, articleVo);
        articleVo.setContent(content);
        articleVo.setStaticUrl(htmlFilePath);

        kafkaTemplate.send(ArticleConstants.ARTICLE_ES_SYNC_TOPIC, JSON.toJSONString(articleVo));


    }


}